package com.vecspace.framework.httphandler;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.vecspace.core.support.BeansContextUtil;
import com.vecspace.dayu.code.pojo.Project;
import com.vecspace.dayu.code.pojo.ProjectUser;
import com.vecspace.dayu.code.service.ProjectService;
import com.vecspace.dayu.code.service.ProjectUserService;
import com.vecspace.dayu.code.service.UserPropertyService;
import com.vecspace.dayu.code.vo.UserDataVO;
import com.vecspace.exception.HException;
import com.vecspace.security.model.SSOConsts;
import com.vecspace.security.proxy.service.LoginManager;
import com.vecspace.utils.Assert;
import com.vecspace.web.HttpContextThreadLocal;
import com.vecspace.web.servlet.model.BaseController;
import com.vecspace.web.servlet.model.FtlViewModel;
import com.vecspace.web.servlet.model.HController;
import com.vecspace.web.servlet.model.Param;
import com.vecspace.web.servlet.model.Path;
import com.vecspace.web.servlet.model.ViewModel;

@HController("loginHandler")
public class LoginHandler extends BaseController{
	
	@Value("${app.deployTime}")
	private String deployTime;
	
	@Path("deployTime")
	public String deployTime() {
		return "deployTime:"+deployTime;
	}
	
	@Path("info")
	public String info() {
		return "deployTime:"+deployTime;
	}
	
	private static final String login_project_id_key = "login_project_id";
	/**
	 * 
	 * @param loginId
	 * @param password
	 * @return
	 * @throws Exception 
	 * @设计者: wanghua
	 * @author: wanghua
	 */
	@Path("checkLogin")
	public UserDataVO checkLogin(@Param("loginId")String loginId, @Param("password")String password) throws Exception {
		Assert.throwz(StringUtils.isNotEmpty(loginId), "登录id不能为空");
		//Assert.throwz(StringUtils.isNotEmpty(password), "登录密码不能为空");

		HttpServletRequest req = HttpContextThreadLocal.getHttpContext().getHttpRequest();
		HttpSession session = req.getSession();
		
		loginId = loginId.trim();
		String loginIdLow = loginId.toLowerCase();
		
		boolean hasUser = projectUserService.hasUser(loginIdLow);
		if(!hasUser) {
			throw new HException("系统中不存在此用户：" + loginId);
		}else {		
			session.setAttribute(SSOConsts.SESSION_NAME_LOGIN_ID, loginIdLow);
			session.setAttribute(SSOConsts.SESSION_NAME_LOGIN_NAME, loginId);
			UserDataVO userData = getLoginUserDataVO();
			return userData;
		}
	}
	
	/**切换登录的项目
	 * 如果当前登录账号不是此项目的用户，则抛出异常。
	 * @param projectId
	 * @return
	 * @throws Exception 
	 * @author wanghua
	 */
	@Path("changeLoginProject")
	public UserDataVO changeLoginProject(@Param("projectId") Long projectId) throws Exception {
		String loginId = getLoginId();
		ProjectUser projectUser = projectUserService.getProjectUser(loginId, projectId);
		if(projectUser == null || "0".equals(projectUser.getRoleCode())) {
			projectUser = projectUserService.getProjectUser(loginId, -1L);
			if(projectUser == null || "0".equals(projectUser.getRoleCode())) {
				throw new HException("您没有此项目的操作权限");
			}
		}
		//在session中记录当前切换的项目
		HttpSession session = HttpContextThreadLocal.getHttpContext().getHttpSession();
		session.setAttribute("login_project_id_key", projectId);
		
		//保存当前切换的项目
		userPropertyService.saveOrUpdateUserProperty(loginId, login_project_id_key, projectId);
		
		UserDataVO userData = getLoginUserDataVO();
		return userData;
	}
	
	/**获取用户的登录信息
	 * 1、从session中获取loginId
	 * 2、判断用户是否超级管理员
	 * 3、用session中获取当前登录的项目id，如果session中没有项目id，则从用户配置表中获取记录的用户的项目id
	 * 4、判断用户是否是项目的管理员
	 * @return
	 * @throws Exception 
	 * @author wanghua
	 */
	@Path("getLoginUserDataVO")
	public UserDataVO getLoginUserDataVO() throws Exception {
		UserDataVO userData = new UserDataVO();

		String loginId = getLoginId();
		if(loginId == null || loginId.length() == 0) throw new HException("您没有登录！");
		userData.setLoginId(loginId);
		boolean isSuperAdmin = projectUserService.isSuperAdmin(loginId);
		userData.setAdmin(isSuperAdmin);

		HttpSession session = HttpContextThreadLocal.getHttpContext().getHttpSession();
		Long projectId = (Long)session.getAttribute("login_project_id_key");
		if(projectId == null) {
			projectId = userPropertyService.getUserPropertyNum(loginId, login_project_id_key);
			session.setAttribute("login_project_id_key", projectId);
		}
		if(projectId != null && projectId != 0) {
			Project project = projectService.getProject(projectId);
			userData.setProject(project);
			boolean isProjectAdmin = projectUserService.isProjectAdmin(loginId, projectId);
			userData.setProjectAdmin(isProjectAdmin);
		}
		
		return userData;
	}

	@Path("getLoginId")
	public String getLoginId() {
		return LoginManager.getLoginId();
	}

	/**可用段用来保持连接（保持session）的请求，什么事情都不做，*/
	@Path("keepAlive")
	public String keepAlive(){
		this.getHttpRequest().getSession().setAttribute("Last_keepAlive", System.currentTimeMillis());
		return "ok"; 
	}
	
	@Path("isLogon")
	public String isLogon() throws HException{
		String userId = LoginManager.getLoginId();
		Assert.throwz(StringUtils.isNotEmpty(userId), "还没有登录");
		return userId;
	}
		
	@Path("logout")
	public ViewModel logout() throws Exception {
		this.getHttpSession().invalidate();
		Map<String, Object> params = this.getRequestParameters();
		return new FtlViewModel("view/login/login.ftl", params);
	}

	@Path("login")
	public ViewModel login() {
		Map<String, Object> params = this.getRequestParameters();
		return new FtlViewModel("view/login/login.ftl", params);
	}
	
	@Path("resetPassword")
	public ViewModel modifyPassword() {
		Map<String, Object> params = this.getRequestParameters();
		return new FtlViewModel("view/login/resetPassword.ftl", params);
	}
	
	/**遍历所有注册的Controller和Path
	 * @author wanghua
	 * @return
	 */
	@Path("getHandlerPaths")
	public String getHandlerPaths() {
		StringBuilder sb = new StringBuilder(10240);
		Map<String, Object> beansMap = BeansContextUtil.getBeansWithAnnotation(HController.class);
		for(Object bean : beansMap.values()) {
			HController controllerAnno = bean.getClass().getAnnotation(HController.class);
			Method[] methods = bean.getClass().getMethods();
			for(Method method : methods) {
				Path pathAnno = method.getAnnotation(Path.class);
				if(pathAnno != null) {
					sb.append("irest/base/").append(controllerAnno.value()).append("/").append(pathAnno.value()).append("\r\n");
				}
			}
		}
		return sb.toString();
	}
	@Path(value = "getCSCode", httpGet = true)
	public String getCSCode(@Param("className")String className) throws Exception {
		StringBuilder sb = new StringBuilder(4096);
		Class<?> clazz = Class.forName(className);
		Method[] methods = clazz.getDeclaredMethods();
		for(Method method : methods) {
			String name = method.getName();
			if(name.startsWith("get") || name.startsWith("is")) {
				if(method.getParameterCount() == 0) {
					String csPropName = "";
					if(name.startsWith("get")) {
						csPropName = name.substring(3);
					}else if(name.startsWith("is")) {
						csPropName = name.substring(2);
					}
					csPropName = csPropName.substring(0, 1).toUpperCase() + csPropName.substring(1);
					
					Class<?> returnType = method.getReturnType();
					if(returnType.equals(String.class)) {
						sb.append("\t\tpublic string ").append(csPropName).append(" {get; set;}\r\n");
					}else if(returnType.equals(Integer.class) || returnType.equals(int.class)) {
						sb.append("\t\tpublic int? ").append(csPropName).append(" {get; set;}\r\n");
					}else if(returnType.equals(Long.class) || returnType.equals(long.class)) {
						sb.append("\t\tpublic long? ").append(csPropName).append(" {get; set;}\r\n");
					}else if(returnType.equals(Date.class)) {
						sb.append("\t\tpublic DateTime? ").append(csPropName).append(" {get; set;}\r\n");
					}else if(returnType.equals(Boolean.class) || returnType.equals(boolean.class)) {
						sb.append("\t\tpublic bool? ").append(csPropName).append(" {get; set;}\r\n");
					}
				}
			}
		}
		String code = sb.toString();
		System.out.println(code);
		return code;
	}
	
	@Path(value="readHandler", httpGet = true)
	public String readHandler(@Param("className")String className) throws Exception {
		StringBuilder sb = new StringBuilder(4096);
		Class<?> clazz = Class.forName(className);
		Method[] methods = clazz.getDeclaredMethods();
		for(Method method : methods) {
			Path pathAnno = method.getAnnotation(Path.class);
			if(pathAnno != null) {
				String methodName = method.getName();
				String pathName = pathAnno.value();
				
				String returnTypeClassName = method.getReturnType().getSimpleName();
				String csReturnTypeClassName = getCsDataType( method.getReturnType(), method.getGenericReturnType());
				
				String csMethodStr = "\t\tpublic static " + csReturnTypeClassName + " " + pathName + "(";
				String csRequestStr = "\t\t\t";
				if("void".equals(returnTypeClassName)) {
					csRequestStr += "QHttpClient.Execute(getBaseUrl(\""+pathName+"\"), new{";
				}else {
					csRequestStr += csReturnTypeClassName + " obj = QHttpClient.Post<"+returnTypeClassName+">(getBaseUrl(\""+pathName+"\"), new{";					
				}
				
				Parameter[] parameters = method.getParameters();
				int paramIndex = 0;
				for(Parameter param : parameters) {
					Param paramAnno = param.getAnnotation(Param.class);
					if(paramAnno != null) {
						String paramName = paramAnno.value();
						Class<?> paramType = param.getType();
						String csParamType = getCsDataType(paramType, param.getParameterizedType());
						
						if(paramIndex > 0) {
							csMethodStr +=", ";
							csRequestStr += ", ";
						}
						csMethodStr += csParamType+ " " + paramName;
						csRequestStr += paramName+ " = " + paramName;
					}
					++paramIndex;
				}
				if(!"void".equals(returnTypeClassName)) {
					csRequestStr += " });\r\n\t\t\treturn obj;";
				}else {
					csRequestStr += " });";
				}
				
				csMethodStr += ")\r\n\t\t{\r\n" + csRequestStr + "\r\n\t\t}\r\n";
				sb.append(csMethodStr).append("\r\n");
			}
		}
		String code = sb.toString();
		System.out.println(code);
		return code;
	}
	
	private String getCsDataType(Class<?> javaType, Type parameterizedType) {
		String csParamType = "";
		if(javaType.equals(String.class)) {
			csParamType = "string";
		}else if(javaType.equals(Integer.class) || javaType.equals(int.class)) {
			csParamType = "int";
		}else if(javaType.equals(Long.class) || javaType.equals(long.class)) {
			csParamType = "long";
		}else if(javaType.equals(Date.class)) {
			csParamType = "DateTime";
		}else if(javaType.equals(Boolean.class) || javaType.equals(boolean.class)) {
			csParamType = "bool";
		}else if(List.class.isAssignableFrom(javaType)) {
			csParamType = "IList<XXX>";
		}else {
			csParamType = javaType.getSimpleName();
		}
		return csParamType;
	}
	
	@Path("hello")
	public String hello() {
		return "hello world";
	}

	@Autowired
	private ProjectUserService projectUserService;
	@Autowired
	private ProjectService projectService;
	@Autowired
	private UserPropertyService userPropertyService;
}
